home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2002 #11 / Amiga Plus CD - 2002 - No. 11.iso / Tools / Development / ncurses-5.3 / ncurses / tinfo / lib_tparm.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-10-27  |  17.2 KB  |  770 lines

  1. /****************************************************************************
  2.  * Copyright (c) 1998-2001,2002 Free Software Foundation, Inc.              *
  3.  *                                                                          *
  4.  * Permission is hereby granted, free of charge, to any person obtaining a  *
  5.  * copy of this software and associated documentation files (the            *
  6.  * "Software"), to deal in the Software without restriction, including      *
  7.  * without limitation the rights to use, copy, modify, merge, publish,      *
  8.  * distribute, distribute with modifications, sublicense, and/or sell       *
  9.  * copies of the Software, and to permit persons to whom the Software is    *
  10.  * furnished to do so, subject to the following conditions:                 *
  11.  *                                                                          *
  12.  * The above copyright notice and this permission notice shall be included  *
  13.  * in all copies or substantial portions of the Software.                   *
  14.  *                                                                          *
  15.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
  16.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
  17.  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
  18.  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
  19.  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
  20.  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
  21.  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
  22.  *                                                                          *
  23.  * Except as contained in this notice, the name(s) of the above copyright   *
  24.  * holders shall not be used in advertising or otherwise to promote the     *
  25.  * sale, use or other dealings in this Software without prior written       *
  26.  * authorization.                                                           *
  27.  ****************************************************************************/
  28.  
  29. /****************************************************************************
  30.  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
  31.  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
  32.  *     and: Thomas E. Dickey, 1996 on                                       *
  33.  ****************************************************************************/
  34.  
  35. /*
  36.  *    tparm.c
  37.  *
  38.  */
  39.  
  40. #include <curses.priv.h>
  41.  
  42. #include <ctype.h>
  43. #include <term.h>
  44. #include <tic.h>
  45.  
  46. MODULE_ID("$Id: lib_tparm.c,v 1.62 2002/10/05 19:33:24 Frank.Henigman Exp $")
  47.  
  48. /*
  49.  *    char *
  50.  *    tparm(string, ...)
  51.  *
  52.  *    Substitute the given parameters into the given string by the following
  53.  *    rules (taken from terminfo(5)):
  54.  *
  55.  *         Cursor addressing and other strings  requiring  parame-
  56.  *    ters in the terminal are described by a parameterized string
  57.  *    capability, with like escapes %x in  it.   For  example,  to
  58.  *    address  the  cursor, the cup capability is given, using two
  59.  *    parameters: the row and column to  address  to.   (Rows  and
  60.  *    columns  are  numbered  from  zero and refer to the physical
  61.  *    screen visible to the user, not to any  unseen  memory.)  If
  62.  *    the terminal has memory relative cursor addressing, that can
  63.  *    be indicated by
  64.  *
  65.  *         The parameter mechanism uses  a  stack  and  special  %
  66.  *    codes  to manipulate it.  Typically a sequence will push one
  67.  *    of the parameters onto the stack and then print it  in  some
  68.  *    format.  Often more complex operations are necessary.
  69.  *
  70.  *         The % encodings have the following meanings:
  71.  *
  72.  *         %%        outputs `%'
  73.  *         %c        print pop() like %c in printf()
  74.  *         %s        print pop() like %s in printf()
  75.  *           %[[:]flags][width[.precision]][doxXs]
  76.  *                     as in printf, flags are [-+#] and space
  77.  *                     The ':' is used to avoid making %+ or %-
  78.  *                     patterns (see below).
  79.  *
  80.  *         %p[1-9]   push ith parm
  81.  *         %P[a-z]   set dynamic variable [a-z] to pop()
  82.  *         %g[a-z]   get dynamic variable [a-z] and push it
  83.  *         %P[A-Z]   set static variable [A-Z] to pop()
  84.  *         %g[A-Z]   get static variable [A-Z] and push it
  85.  *         %l        push strlen(pop)
  86.  *         %'c'      push char constant c
  87.  *         %{nn}     push integer constant nn
  88.  *
  89.  *         %+ %- %* %/ %m
  90.  *                   arithmetic (%m is mod): push(pop() op pop())
  91.  *         %& %| %^  bit operations: push(pop() op pop())
  92.  *         %= %> %<  logical operations: push(pop() op pop())
  93.  *         %A %O     logical and & or operations for conditionals
  94.  *         %! %~     unary operations push(op pop())
  95.  *         %i        add 1 to first two parms (for ANSI terminals)
  96.  *
  97.  *         %? expr %t thenpart %e elsepart %;
  98.  *                   if-then-else, %e elsepart is optional.
  99.  *                   else-if's are possible ala Algol 68:
  100.  *                   %? c1 %t b1 %e c2 %t b2 %e c3 %t b3 %e c4 %t b4 %e b5 %;
  101.  *
  102.  *    For those of the above operators which are binary and not commutative,
  103.  *    the stack works in the usual way, with
  104.  *            %gx %gy %m
  105.  *    resulting in x mod y, not the reverse.
  106.  */
  107.  
  108. #define STACKSIZE    20
  109.  
  110. typedef struct {
  111.     union {
  112.     int num;
  113.     char *str;
  114.     } data;
  115.     bool num_type;
  116. } stack_frame;
  117.  
  118. NCURSES_EXPORT_VAR(int) _nc_tparm_err = 0;
  119.  
  120. static stack_frame stack[STACKSIZE];
  121. static int stack_ptr;
  122. static const char *tparam_base = "";
  123.  
  124. #ifdef TRACE
  125. static const char *tname;
  126. #endif /* TRACE */
  127.  
  128. static char *out_buff;
  129. static size_t out_size;
  130. static size_t out_used;
  131.  
  132. #if NO_LEAKS
  133. NCURSES_EXPORT(void)
  134. _nc_free_tparm(void)
  135. {
  136.     if (out_buff != 0) {
  137.     FreeAndNull(out_buff);
  138.     out_size = 0;
  139.     out_used = 0;
  140.     }
  141. }
  142. #endif
  143.  
  144. static inline void
  145. get_space(size_t need)
  146. {
  147.     need += out_used;
  148.     if (need > out_size) {
  149.     out_size = need * 2;
  150.     out_buff = typeRealloc(char, out_size, out_buff);
  151.     if (out_buff == 0)
  152.         _nc_err_abort(MSG_NO_MEMORY);
  153.     }
  154. }
  155.  
  156. static inline void
  157. save_text(const char *fmt, const char *s, int len)
  158. {
  159.     size_t s_len = strlen(s);
  160.     if (len > (int) s_len)
  161.     s_len = len;
  162.  
  163.     get_space(s_len + 1);
  164.  
  165.     (void) sprintf(out_buff + out_used, fmt, s);
  166.     out_used += strlen(out_buff + out_used);
  167. }
  168.  
  169. static inline void
  170. save_number(const char *fmt, int number, int len)
  171. {
  172.     if (len < 30)
  173.     len = 30;        /* actually log10(MAX_INT)+1 */
  174.  
  175.     get_space((unsigned) len + 1);
  176.  
  177.     (void) sprintf(out_buff + out_used, fmt, number);
  178.     out_used += strlen(out_buff + out_used);
  179. }
  180.  
  181. static inline void
  182. save_char(int c)
  183. {
  184.     if (c == 0)
  185.     c = 0200;
  186.     get_space(1);
  187.     out_buff[out_used++] = c;
  188. }
  189.  
  190. static inline void
  191. npush(int x)
  192. {
  193.     if (stack_ptr < STACKSIZE) {
  194.     stack[stack_ptr].num_type = TRUE;
  195.     stack[stack_ptr].data.num = x;
  196.     stack_ptr++;
  197.     } else {
  198.     DEBUG(2, ("npush: stack overflow: %s", _nc_visbuf(tparam_base)));
  199.     _nc_tparm_err++;
  200.     }
  201. }
  202.  
  203. static inline int
  204. npop(void)
  205. {
  206.     int result = 0;
  207.     if (stack_ptr > 0) {
  208.     stack_ptr--;
  209.     if (stack[stack_ptr].num_type)
  210.         result = stack[stack_ptr].data.num;
  211.     } else {
  212.     DEBUG(2, ("npop: stack underflow: %s", _nc_visbuf(tparam_base)));
  213.     _nc_tparm_err++;
  214.     }
  215.     return result;
  216. }
  217.  
  218. static inline void
  219. spush(char *x)
  220. {
  221.     if (stack_ptr < STACKSIZE) {
  222.     stack[stack_ptr].num_type = FALSE;
  223.     stack[stack_ptr].data.str = x;
  224.     stack_ptr++;
  225.     } else {
  226.     DEBUG(2, ("spush: stack overflow: %s", _nc_visbuf(tparam_base)));
  227.     _nc_tparm_err++;
  228.     }
  229. }
  230.  
  231. static inline char *
  232. spop(void)
  233. {
  234.     static char dummy[] = "";    /* avoid const-cast */
  235.     char *result = dummy;
  236.     if (stack_ptr > 0) {
  237.     stack_ptr--;
  238.     if (!stack[stack_ptr].num_type && stack[stack_ptr].data.str != 0)
  239.         result = stack[stack_ptr].data.str;
  240.     } else {
  241.     DEBUG(2, ("spop: stack underflow: %s", _nc_visbuf(tparam_base)));
  242.     _nc_tparm_err++;
  243.     }
  244.     return result;
  245. }
  246.  
  247. static inline const char *
  248. parse_format(const char *s, char *format, int *len)
  249. {
  250.     bool done = FALSE;
  251.     bool allowminus = FALSE;
  252.     bool dot = FALSE;
  253.     bool err = FALSE;
  254.     char *fmt = format;
  255.     int my_width = 0;
  256.     int my_prec = 0;
  257.     int value = 0;
  258.  
  259.     *len = 0;
  260.     *format++ = '%';
  261.     while (*s != '\0' && !done) {
  262.     switch (*s) {
  263.     case 'c':        /* FALLTHRU */
  264.     case 'd':        /* FALLTHRU */
  265.     case 'o':        /* FALLTHRU */
  266.     case 'x':        /* FALLTHRU */
  267.     case 'X':        /* FALLTHRU */
  268.     case 's':
  269.         *format++ = *s;
  270.         done = TRUE;
  271.         break;
  272.     case '.':
  273.         *format++ = *s++;
  274.         if (dot) {
  275.         err = TRUE;
  276.         } else {        /* value before '.' is the width */
  277.         dot = TRUE;
  278.         my_width = value;
  279.         }
  280.         value = 0;
  281.         break;
  282.     case '#':
  283.         *format++ = *s++;
  284.         break;
  285.     case ' ':
  286.         *format++ = *s++;
  287.         break;
  288.     case ':':
  289.         s++;
  290.         allowminus = TRUE;
  291.         break;
  292.     case '-':
  293.         if (allowminus) {
  294.         *format++ = *s++;
  295.         } else {
  296.         done = TRUE;
  297.         }
  298.         break;
  299.     default:
  300.         if (isdigit(UChar(*s))) {
  301.         value = (value * 10) + (*s - '0');
  302.         if (value > 10000)
  303.             err = TRUE;
  304.         *format++ = *s++;
  305.         } else {
  306.         done = TRUE;
  307.         }
  308.     }
  309.     }
  310.  
  311.     /*
  312.      * If we found an error, ignore (and remove) the flags.
  313.      */
  314.     if (err) {
  315.     my_width = my_prec = value = 0;
  316.     format = fmt;
  317.     *format++ = '%';
  318.     *format++ = *s;
  319.     }
  320.  
  321.     /*
  322.      * Any value after '.' is the precision.  If we did not see '.', then
  323.      * the value is the width.
  324.      */
  325.     if (dot)
  326.     my_prec = value;
  327.     else
  328.     my_width = value;
  329.  
  330.     *format = '\0';
  331.     /* return maximum string length in print */
  332.     *len = (my_width > my_prec) ? my_width : my_prec;
  333.     return s;
  334. }
  335.  
  336. #define isUPPER(c) ((c) >= 'A' && (c) <= 'Z')
  337. #define isLOWER(c) ((c) >= 'a' && (c) <= 'z')
  338.  
  339. static inline char *
  340. tparam_internal(const char *string, va_list ap)
  341. {
  342. #define NUM_VARS 26
  343.     char *p_is_s[9];
  344.     long param[9];
  345.     int lastpop;
  346.     int popcount;
  347.     int number;
  348.     int len;
  349.     int level;
  350.     int x, y;
  351.     int i;
  352.     size_t len2;
  353.     register const char *cp;
  354.     static size_t len_fmt;
  355.     static char dummy[] = "";
  356.     static char *format;
  357.     static int dynamic_var[NUM_VARS];
  358.     static int static_vars[NUM_VARS];
  359.  
  360.     out_used = 0;
  361.     if (string == NULL)
  362.     return NULL;
  363.  
  364.     if ((len2 = strlen(string)) > len_fmt) {
  365.     len_fmt = len2 + len_fmt + 2;
  366.     if ((format = typeRealloc(char, len_fmt, format)) == 0)
  367.           return 0;
  368.     }
  369.  
  370.     /*
  371.      * Find the highest parameter-number referred to in the format string.
  372.      * Use this value to limit the number of arguments copied from the
  373.      * variable-length argument list.
  374.      */
  375.  
  376.     number = 0;
  377.     lastpop = -1;
  378.     popcount = 0;
  379.     memset(p_is_s, 0, sizeof(p_is_s));
  380.  
  381.     /*
  382.      * Analyze the string to see how many parameters we need from the varargs
  383.      * list, and what their types are.  We will only accept string parameters
  384.      * if they appear as a %l or %s format following an explicit parameter
  385.      * reference (e.g., %p2%s).  All other parameters are numbers.
  386.      *
  387.      * 'number' counts coarsely the number of pop's we see in the string, and
  388.      * 'popcount' shows the highest parameter number in the string.  We would
  389.      * like to simply use the latter count, but if we are reading termcap
  390.      * strings, there may be cases that we cannot see the explicit parameter
  391.      * numbers.
  392.      */
  393.     for (cp = string; (cp - string) < (int) len2;) {
  394.     if (*cp == '%') {
  395.         cp++;
  396.         cp = parse_format(cp, format, &len);
  397.         switch (*cp) {
  398.         default:
  399.         break;
  400.  
  401.         case 'd':        /* FALLTHRU */
  402.         case 'o':        /* FALLTHRU */
  403.         case 'x':        /* FALLTHRU */
  404.         case 'X':        /* FALLTHRU */
  405.         case 'c':        /* FALLTHRU */
  406.         number++;
  407.         lastpop = -1;
  408.         break;
  409.  
  410.         case 'l':
  411.         case 's':
  412.         if (lastpop > 0)
  413.             p_is_s[lastpop - 1] = dummy;
  414.         ++number;
  415.         break;
  416.  
  417.         case 'p':
  418.         cp++;
  419.         i = (*cp - '0');
  420.         if (i >= 0 && i <= 9) {
  421.             lastpop = i;
  422.             if (lastpop > popcount)
  423.             popcount = lastpop;
  424.         }
  425.         break;
  426.  
  427.         case 'P':
  428.         ++number;
  429.         ++cp;
  430.         break;
  431.  
  432.         case 'g':
  433.         cp++;
  434.         break;
  435.  
  436.         case S_QUOTE:
  437.         cp += 2;
  438.         lastpop = -1;
  439.         break;
  440.  
  441.         case L_BRACE:
  442.         cp++;
  443.         while (*cp >= '0' && *cp <= '9') {
  444.             cp++;
  445.         }
  446.         break;
  447.  
  448.         case '+':
  449.         case '-':
  450.         case '*':
  451.         case '/':
  452.         case 'm':
  453.         case 'A':
  454.         case 'O':
  455.         case '&':
  456.         case '|':
  457.         case '^':
  458.         case '=':
  459.         case '<':
  460.         case '>':
  461.         lastpop = -1;
  462.         number += 2;
  463.         break;
  464.  
  465.         case '!':
  466.         case '~':
  467.         lastpop = -1;
  468.         ++number;
  469.         break;
  470.  
  471.         case 'i':
  472.         lastpop = -1;
  473.         if (popcount < 2)
  474.             popcount = 2;
  475.         break;
  476.         }
  477.     }
  478.     if (*cp != '\0')
  479.         cp++;
  480.     }
  481.  
  482.     if (number > 9)
  483.     number = 9;
  484.     for (i = 0; i < max(popcount, number); i++) {
  485.     /*
  486.      * A few caps (such as plab_norm) have string-valued parms.
  487.      * We'll have to assume that the caller knows the difference, since
  488.      * a char* and an int may not be the same size on the stack.  The
  489.      * normal prototype for this uses 9 long's, which is consistent with
  490.      * our va_arg() usage.
  491.      */
  492.     if (p_is_s[i] != 0) {
  493.         p_is_s[i] = va_arg(ap, char *);
  494.     } else {
  495.         param[i] = va_arg(ap, long int);
  496.     }
  497.     }
  498.  
  499.     /*
  500.      * This is a termcap compatibility hack.  If there are no explicit pop
  501.      * operations in the string, load the stack in such a way that
  502.      * successive pops will grab successive parameters.  That will make
  503.      * the expansion of (for example) \E[%d;%dH work correctly in termcap
  504.      * style, which means tparam() will expand termcap strings OK.
  505.      */
  506.     stack_ptr = 0;
  507.     if (popcount == 0) {
  508.     popcount = number;
  509.     for (i = number - 1; i >= 0; i--)
  510.         npush(param[i]);
  511.     }
  512. #ifdef TRACE
  513.     if (_nc_tracing & TRACE_CALLS) {
  514.     for (i = 0; i < popcount; i++) {
  515.         if (p_is_s[i] != 0)
  516.         save_text(", %s", _nc_visbuf(p_is_s[i]), 0);
  517.         else
  518.         save_number(", %d", param[i], 0);
  519.     }
  520.     _tracef(T_CALLED("%s(%s%s)"), tname, _nc_visbuf(string), out_buff);
  521.     out_used = 0;
  522.     }
  523. #endif /* TRACE */
  524.  
  525.     while (*string) {
  526.     if (*string != '%') {
  527.         save_char(*string);
  528.     } else {
  529.         tparam_base = string++;
  530.         string = parse_format(string, format, &len);
  531.         switch (*string) {
  532.         default:
  533.         break;
  534.         case '%':
  535.         save_char('%');
  536.         break;
  537.  
  538.         case 'd':        /* FALLTHRU */
  539.         case 'o':        /* FALLTHRU */
  540.         case 'x':        /* FALLTHRU */
  541.         case 'X':        /* FALLTHRU */
  542.         save_number(format, npop(), len);
  543.         break;
  544.  
  545.         case 'c':        /* FALLTHRU */
  546.         save_char(npop());
  547.         break;
  548.  
  549.         case 'l':
  550.         save_number("%d", (int) strlen(spop()), 0);
  551.         break;
  552.  
  553.         case 's':
  554.         save_text(format, spop(), len);
  555.         break;
  556.  
  557.         case 'p':
  558.         string++;
  559.         i = (*string - '1');
  560.         if (i >= 0 && i < 9) {
  561.             if (p_is_s[i])
  562.             spush(p_is_s[i]);
  563.             else
  564.             npush(param[i]);
  565.         }
  566.         break;
  567.  
  568.         case 'P':
  569.         string++;
  570.         if (isUPPER(*string)) {
  571.             i = (*string - 'A');
  572.             static_vars[i] = npop();
  573.         } else if (isLOWER(*string)) {
  574.             i = (*string - 'a');
  575.             dynamic_var[i] = npop();
  576.         }
  577.         break;
  578.  
  579.         case 'g':
  580.         string++;
  581.         if (isUPPER(*string)) {
  582.             i = (*string - 'A');
  583.             npush(static_vars[i]);
  584.         } else if (isLOWER(*string)) {
  585.             i = (*string - 'a');
  586.             npush(dynamic_var[i]);
  587.         }
  588.         break;
  589.  
  590.         case S_QUOTE:
  591.         string++;
  592.         npush(*string);
  593.         string++;
  594.         break;
  595.  
  596.         case L_BRACE:
  597.         number = 0;
  598.         string++;
  599.         while (*string >= '0' && *string <= '9') {
  600.             number = number * 10 + *string - '0';
  601.             string++;
  602.         }
  603.         npush(number);
  604.         break;
  605.  
  606.         case '+':
  607.         npush(npop() + npop());
  608.         break;
  609.  
  610.         case '-':
  611.         y = npop();
  612.         x = npop();
  613.         npush(x - y);
  614.         break;
  615.  
  616.         case '*':
  617.         npush(npop() * npop());
  618.         break;
  619.  
  620.         case '/':
  621.         y = npop();
  622.         x = npop();
  623.         npush(y ? (x / y) : 0);
  624.         break;
  625.  
  626.         case 'm':
  627.         y = npop();
  628.         x = npop();
  629.         npush(y ? (x % y) : 0);
  630.         break;
  631.  
  632.         case 'A':
  633.         npush(npop() && npop());
  634.         break;
  635.  
  636.         case 'O':
  637.         npush(npop() || npop());
  638.         break;
  639.  
  640.         case '&':
  641.         npush(npop() & npop());
  642.         break;
  643.  
  644.         case '|':
  645.         npush(npop() | npop());
  646.         break;
  647.  
  648.         case '^':
  649.         npush(npop() ^ npop());
  650.         break;
  651.  
  652.         case '=':
  653.         y = npop();
  654.         x = npop();
  655.         npush(x == y);
  656.         break;
  657.  
  658.         case '<':
  659.         y = npop();
  660.         x = npop();
  661.         npush(x < y);
  662.         break;
  663.  
  664.         case '>':
  665.         y = npop();
  666.         x = npop();
  667.         npush(x > y);
  668.         break;
  669.  
  670.         case '!':
  671.         npush(!npop());
  672.         break;
  673.  
  674.         case '~':
  675.         npush(~npop());
  676.         break;
  677.  
  678.         case 'i':
  679.         if (p_is_s[0] == 0)
  680.             param[0]++;
  681.         if (p_is_s[1] == 0)
  682.             param[1]++;
  683.         break;
  684.  
  685.         case '?':
  686.         break;
  687.  
  688.         case 't':
  689.         x = npop();
  690.         if (!x) {
  691.             /* scan forward for %e or %; at level zero */
  692.             string++;
  693.             level = 0;
  694.             while (*string) {
  695.             if (*string == '%') {
  696.                 string++;
  697.                 if (*string == '?')
  698.                 level++;
  699.                 else if (*string == ';') {
  700.                 if (level > 0)
  701.                     level--;
  702.                 else
  703.                     break;
  704.                 } else if (*string == 'e' && level == 0)
  705.                 break;
  706.             }
  707.  
  708.             if (*string)
  709.                 string++;
  710.             }
  711.         }
  712.         break;
  713.  
  714.         case 'e':
  715.         /* scan forward for a %; at level zero */
  716.         string++;
  717.         level = 0;
  718.         while (*string) {
  719.             if (*string == '%') {
  720.             string++;
  721.             if (*string == '?')
  722.                 level++;
  723.             else if (*string == ';') {
  724.                 if (level > 0)
  725.                 level--;
  726.                 else
  727.                 break;
  728.             }
  729.             }
  730.  
  731.             if (*string)
  732.             string++;
  733.         }
  734.         break;
  735.  
  736.         case ';':
  737.         break;
  738.  
  739.         }            /* endswitch (*string) */
  740.     }            /* endelse (*string == '%') */
  741.  
  742.     if (*string == '\0')
  743.         break;
  744.  
  745.     string++;
  746.     }                /* endwhile (*string) */
  747.  
  748.     get_space(1);
  749.     out_buff[out_used] = '\0';
  750.  
  751.     T((T_RETURN("%s"), _nc_visbuf(out_buff)));
  752.     return (out_buff);
  753. }
  754.  
  755. NCURSES_EXPORT(char *)
  756. tparm(NCURSES_CONST char *string,...)
  757. {
  758.     va_list ap;
  759.     char *result;
  760.  
  761.     _nc_tparm_err = 0;
  762.     va_start(ap, string);
  763. #ifdef TRACE
  764.     tname = "tparm";
  765. #endif /* TRACE */
  766.     result = tparam_internal(string, ap);
  767.     va_end(ap);
  768.     return result;
  769. }
  770.